Skip to content

Comments

feat(python): auto-activate venv before hook execution#347

Open
mwbrooks wants to merge 7 commits intomwbrooks-python-venvfrom
mwbrooks-python-venv-activation
Open

feat(python): auto-activate venv before hook execution#347
mwbrooks wants to merge 7 commits intomwbrooks-python-venvfrom
mwbrooks-python-venv-activation

Conversation

@mwbrooks
Copy link
Member

@mwbrooks mwbrooks commented Feb 21, 2026

Changelog

When running Slack CLI commands in a Bolt Python project, the CLI will attempt to automatically activate the venv. This will allow commands that use the slack-cli-hooks Python package to safely and successfully run even when the terminal system doesn't have the virtual environment activated.

Summary

This pull request gives Python the "create and run" experience that Node and Deno enjoy.

It enables auto-activation of venv, when it exists, so that commands can run safely and successfully even when the terminal session doesn't have a virtual environment activated. When the .venv is missing, the CLI will continue like normal.

Test coverage:

  • I noticed that the test coverage is reported as being low
  • Checking locally, it should be higher than reported
  • I'm hopeful that once mwbrooks-python-venv is merged, this branch will report higher coverage

Merge order:

  • This PR depends on the branch mwbrooks-python-venv
  • First merge mwbrooks-python-venv then merge this PR into main

Preview

2026-02-20-create-run-python.mov

Reviewers

Bolt for Python:

$ lack create my-test-app/
# → Select "AI Agent App"
# → Select "Bolt for Python"

# Validate output:
# → Confirm: "Created virtual environment at .venv"
# → Confirm: "Installed dependencies from pyproject.toml"
# → Confirm: "Installed dependencies from requirements.txt"
# → Confirm: No errors

# Run the app
$ cd my-test-app/
$ lack run
# → Confirm: App starts

# Clean up
$ cd ../
$ rm -rf my-test-app/

Bolt for JavaScript:

$ lack create my-test-app/
# → Select "AI Agent App"
# → Select "Bolt for JavaScript" <---- Not Python

# Validate output:
# → Confirm: No errors

# Run the app
$ cd my-test-app/
$ lack run
# → Confirm: App starts

# Clean up
$ cd ../
$ rm -rf my-test-app/

Requirements

Set VIRTUAL_ENV, prepend venv bin to PATH, and unset PYTHONHOME on the
CLI process before any hooks run. This lets hook scripts (e.g.
get-hooks, start, deploy) resolve the venv's Python and installed
packages without requiring developers to manually activate the venv.

Activation happens in InitSDKConfig after finding the project root and
before reading/executing hooks. It is a no-op when no .venv exists, so
non-Python projects are unaffected. Failure is non-fatal (debug log).
Return a boolean from ActivateVenvIfPresent to indicate whether
activation occurred, and log a debug message on success.
@mwbrooks mwbrooks added this to the Next Release milestone Feb 21, 2026
@mwbrooks mwbrooks self-assigned this Feb 21, 2026
@mwbrooks mwbrooks added enhancement M-T: A feature request for new functionality changelog Use on updates to be included in the release notes semver:minor Use on pull requests to describe the release version increment area:bolt-python Related to github.com/slackapi/bolt-python labels Feb 21, 2026
@codecov
Copy link

codecov bot commented Feb 21, 2026

Codecov Report

❌ Patch coverage is 41.66667% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.70%. Comparing base (180d499) to head (f8755c9).

Files with missing lines Patch % Lines
internal/runtime/python/python.go 50.00% 4 Missing and 4 partials ⚠️
internal/shared/clients.go 0.00% 2 Missing and 2 partials ⚠️
internal/slackdeps/os.go 0.00% 2 Missing ⚠️
Additional details and impacted files
@@                   Coverage Diff                    @@
##           mwbrooks-python-venv     #347      +/-   ##
========================================================
- Coverage                 64.77%   64.70%   -0.08%     
========================================================
  Files                       212      212              
  Lines                     17860    17884      +24     
========================================================
+ Hits                      11569    11571       +2     
- Misses                     5212     5224      +12     
- Partials                   1079     1089      +10     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member Author

@mwbrooks mwbrooks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments for those kind reviewers! 🙇🏻

Comment on lines 106 to 112
if err := os.Setenv("VIRTUAL_ENV", venvPath); err != nil {
return false, err
}
if err := os.Setenv("PATH", binDir+string(filepath.ListSeparator)+os.Getenv("PATH")); err != nil {
return false, err
}
os.Unsetenv("PYTHONHOME")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I imagine we should create wrappers for these calls in our slackdeps.Os 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I updated this PR to use slackdeps.Os and added slackdeps.Os.lookupEnv.

Comment on lines 69 to 76
// ActivatePythonVenvIfPresent activates a Python virtual environment if one
// exists in the given project directory. This sets VIRTUAL_ENV, prepends the
// venv bin directory to PATH, and unsets PYTHONHOME on the current process so
// that child processes (hook scripts) inherit the activated venv.
func ActivatePythonVenvIfPresent(fs afero.Fs, projectDir string) (bool, error) {
return python.ActivateVenvIfPresent(fs, projectDir)
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: While it feels wrong to have Python in the generic runtime this allows us to activate it for any project. We could move this into the Python runtime and think of a more general function that could be used across all runtimes.

Upside of this approach is that JS projects that include a .venv (perhaps for scripts) can be activated automatically.

if activated, err := runtime.ActivatePythonVenvIfPresent(c.Fs, dirPath); err != nil {
c.IO.PrintDebug(ctx, "failed to activate Python virtual environment: %s", err)
} else if activated {
c.IO.PrintDebug(ctx, "Activated Python virtual environment .venv")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note: I'd love to display this in the regular output, but it's tough to get a nice format because it can be displayed in many different situations.

…bility

Add Unsetenv to the Os interface/implementation/mock and refactor
ActivateVenvIfPresent to accept types.Os instead of calling the os
package directly. This allows the test to use mocks instead of mutating
the real process environment.
@mwbrooks mwbrooks marked this pull request as ready for review February 21, 2026 03:06
@mwbrooks mwbrooks requested a review from a team as a code owner February 21, 2026 03:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:bolt-python Related to github.com/slackapi/bolt-python changelog Use on updates to be included in the release notes enhancement M-T: A feature request for new functionality semver:minor Use on pull requests to describe the release version increment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant